package com.xixibaby.redis.aspect;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.xixibaby.core.Assert;
import com.xixibaby.core.SuperAspect;
import com.xixibaby.core.SuperRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@Slf4j
@org.aspectj.lang.annotation.Aspect
public class RedisLockAspect implements SuperAspect {


    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Pointcut("@annotation(com.xixibaby.redis.aspect.RedisLock)")
    public void pointCut() {

    }

    @Around(value = "pointCut()&&@annotation(redisCache)")
    public Object pointProcess(ProceedingJoinPoint point, RedisLock redisCache) throws Throwable {

        Object[] args = point.getArgs();
        Object obj = args[0];
        String url = getUrl(point);
        if(obj instanceof SuperRequest){
            String s = JSONObject.toJSONString(obj);
            String s1 = SecureUtil.md5(s);
            RLock lock = redissonClient.getLock(s1);
            lock.lock(redisCache.ttl(), TimeUnit.SECONDS);
            log.info("RedisLock: 接口名称【{}】，锁信息【{}】【{}】,",url,redisCache.ttl(),s1);
            Object proceed = point.proceed();
            log.info("RedisLock释放锁: 接口名称【{}】，锁信息【{}】【{}】,",url,redisCache.ttl(),s1);
            lock.unlock();
            return proceed;
        }else{
            return point.proceed();
        }
    }


    public <T> T getMethodSignature(ProceedingJoinPoint point, Function<MethodSignature,T> function){
        Signature sig = point.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        return function.apply(msig);
    }

    private String getUrl(ProceedingJoinPoint point) throws NoSuchMethodException {
        MethodSignature msig = getMethodSignature(point, methodSignature -> methodSignature);
        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        PostMapping mapping =currentMethod.getAnnotation(PostMapping.class);
        if(Assert.empty(mapping)){
            GetMapping mapping2 =currentMethod.getAnnotation(GetMapping.class);
            return mapping2.value()[0];
        }
        return  mapping.value()[0];
    }



}
